﻿//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Description: Validation Rule to validate that the expected partial or 
//              complete response matches the actual response body
//
//------------------------------------------------------------------------------
using System;
using System.ComponentModel;
using Microsoft.VisualStudio.TestTools.WebTesting;
using System.IO;

namespace WebAndLoadTestPluginsAndRules
{
    [DisplayName("Response Body")]
    [Description("Validates that the expected partial or complete response matches the actual response body." +
                " Each line of the expected and actual response is trimmed for leading" +
                " and trailing spaces before comparison.")]
    public class ValidateResponseBody : ValidationRule
    {
        // The File Path
        private string filePath;

        [DisplayName("Required File Path")]
        [Description("The absolute file path containing the expected partial or complete response.")]
        public string requiredfilepath
        {
            get { return filePath; }
            set { filePath = value; }
        }

        //  Should the Case be ignored while comparing
        private bool ignoreCaseValue = false;

        [DisplayName("Ignore Case")]
        [Description("Whether case should be ignored or not while comparing the file's contents.")]
        [DefaultValue(false)]
        public bool IgnoreCase
        {
            get { return ignoreCaseValue; }
            set { ignoreCaseValue = value; }
        }

        // Validate is called with the test case Context and the request context.
        // These allow the rule to examine both the request and the response.
        //---------------------------------------------------------------------
        public override void Validate(object sender, ValidationEventArgs e)
        {
            bool validated = false;
            bool firstLineFound = false;
            uint i = 0;
            string debugMsg = String.Empty;

            try
            {
                using (FileStream fs = File.Open(requiredfilepath, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    string[] lines = File.ReadAllLines(requiredfilepath);

                    StringReader stringReader = new StringReader(e.Response.BodyString);

                    //  Reads a line from the StringReader, compares with current line of the expected
                    //  response. If it passes, it moves on, else, it logs the error and breaks
                    while (true)
                    {
                        string aLine = stringReader.ReadLine();
                        
                        //  Making sure that we still have something to compare with
                        if (aLine != null && i < lines.Length)
                        {
                            //  Trim the expected and actual responses for leading and trailing spaces before comparison
                            if (aLine.Trim().Equals(lines[i].Trim(), (ignoreCaseValue == true) ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture))
                            {
                                i++;
                                //  This is to figure out whether we've found the first expected line or not
                                if (firstLineFound == false)
                                    firstLineFound = true;
                                debugMsg = debugMsg + aLine + "\r\n";
                            }
                            else if (firstLineFound)
                            {
                                //  If we have found the first line then we should throw an error if we're here
                                e.Message = String.Format("Expected line '{0}', found '{1}'. Expected line is missing or non-contiguous", lines[i], aLine);
                                break;
                            }
                        }
                        else
                        {
                            if (i == lines.Length)
                            {
                                validated = true;
                                //e.Message = debugMsg;
                            }
                            else if (aLine == null)
                            {
                                //  We haven't found the first line at all
                                e.Message = String.Format("Reached end of response while looking for line '{0}' in the response", lines[i]);
                            }

                            break;
                        }
                        
                    }

                }

                e.IsValid = validated;
            }
            catch (Exception ex)
            {
                e.IsValid = validated;
                e.Message = String.Format("An exception occurred. Input filename: '{0}'. Stack Dump: {1}", filePath, ex);
            }
            
        }
    }
}